package com.smileymedia.smil;


import java.io.CharArrayWriter;
import java.util.Enumeration;
import java.util.Map;
import java.util.Stack;
import java.util.Map.Entry;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

import com.smileymedia.smil.content.AudioContent;
import com.smileymedia.smil.content.ImageContent;
import com.smileymedia.smil.content.SmilContent;
import com.smileymedia.smil.content.TextContent;
import com.smileymedia.smil.stage.ParallelTimeline;
import com.smileymedia.smil.stage.SequenceTimeline;
import com.smileymedia.smil.stage.Stage;
import com.smileymedia.smil.stage.Timeline;
import com.smileymedia.util.SDCardUtil;
/**
 * ContentHanlder responsible for parsing the SMIL xml document, this only handles a subset of smil
 * http://onjava.com/pub/a/onjava/2002/06/26/xml.html?page=2
 * @author gbugaj
 *
 */
public class SmilContentHandler extends DefaultHandler {

	/**
	 * Get the inner content of the visited element
	 */
	public void characters(char[] ch, int start, int length)  throws SAXException {		
		if(mCollectContent){
			mContents.write(ch, start, length);
		}
	}

	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		
		Log.d(TAG, " -- Starting --"+localName);
		if(TAG_SMIL.equalsIgnoreCase(localName)){
			mStage=new Stage();
			mStack.push(mStage);
		}else if(TAG_SEQ.equalsIgnoreCase(localName)){
			Timeline timeLine=new SequenceTimeline();
			mStack.push(timeLine);
		}else if(TAG_PAR.equalsIgnoreCase(localName)){
			Timeline timeLine=new ParallelTimeline();
			mStack.push(timeLine);
		}else if(TAG_PARAMETER.equalsIgnoreCase(localName)){	
			mCollectContent=false;
			mStack.push(attributes.getValue("name"));
			mStack.push(attributes.getValue("value"));
		}

		else  if(
				TAG_AUDIO.equalsIgnoreCase(localName) || 
				TAG_IMG.equalsIgnoreCase(localName) ||
				TAG_TEXT.equalsIgnoreCase(localName) 
		){

			SmilContent content = null;
			if(TAG_AUDIO.equalsIgnoreCase(localName)){
				content =  new AudioContent();
				content.setDowloadable(true);
			}else if(TAG_IMG.equalsIgnoreCase(localName)){
				content =  new ImageContent();
				content.setDowloadable(true);

			}else if(TAG_TEXT.equalsIgnoreCase(localName)){
				mContents.reset();
				mCollectContent=true;
				
				content =  new TextContent();
				content.setDowloadable(false);

			}else{				
				Log.w(TAG, "Unknown tag: "+localName);
				return;
			}

			//Extract properties from attributes
			double duration=getAttributeValueDouble(attributes, "duration", 0.0d);
			double startTime=getAttributeValueDouble(attributes, "begin", 0.0d);

			content.setSource(attributes.getValue("src"));

			Timeline timeLine=new Timeline();
			timeLine.setStartTime(startTime);
			timeLine.setDuration(duration);			
			timeLine.setContent(content);

			mStack.push(timeLine);
		}
	}

	/**
	 * Get value of attribute
	 * @param atts 
	 * @param attributeName to get value for
	 * @param defaultValue to return if attribute is not present
	 * @return
	 */
	private double getAttributeValueDouble(Attributes atts, String attributeName, double defaultValue) {
		String value = atts.getValue(attributeName);
		if(value == null){
			return defaultValue;
		}	
		return Double.parseDouble(value);	
	}


	public void endElement(String uri, String localName, String qName)	throws SAXException {		
		Log.d(TAG, " -- Ending --"+localName);
		//Closing root
		Object obj= null;
		if(TAG_SMIL.equalsIgnoreCase(localName)){
			obj=mStack.pop();
			mStage=(Stage) obj;
		} else if(TAG_SEQ.equalsIgnoreCase(localName)){
			obj=mStack.pop();//Our value to Add
			mStage = (Stage) mStack.peek();
			mStage.add((Timeline) obj);			
		} else if(TAG_PAR.equalsIgnoreCase(localName)){
			obj=mStack.pop();//Our value to Add
			mStage = (Stage) mStack.peek();
			mStage.add((Timeline) obj);			
		} else if(TAG_PARAMETER.equalsIgnoreCase(localName)){
			String value=(String) mStack.pop();
			String key=(String) mStack.pop();
			obj=mStack.peek();//Our value to Add
			((Timeline) obj).getContent().mParameters.put(key, value);
		} else  if(
				TAG_AUDIO.equalsIgnoreCase(localName) || 
				TAG_IMG.equalsIgnoreCase(localName) ||
				TAG_TEXT.equalsIgnoreCase(localName) 
		){
			obj=mStack.pop();//Our value to Add

			if(TAG_TEXT.equalsIgnoreCase(localName) ){
				Log.w(TAG, " - Content= "+mContents);

				((Timeline) obj).getContent().setSource(mContents.toString());
			}

			Object container = mStack.peek();
			//It is added directly to stage
			if(container instanceof Stage){
				mStage = (Stage) container;
				mStage.add((Timeline) obj);	
			}

			//Added to SequenceTimeLine
			if(container instanceof SequenceTimeline){
				SequenceTimeline timeline = (SequenceTimeline) container;
				timeline.add((Timeline) obj);	
			}else 	if(container instanceof ParallelTimeline){
				ParallelTimeline timeline = (ParallelTimeline) container;
				timeline.add((Timeline) obj);	
			}
			Log.w(TAG, obj.toString());
		}
	}

	public Stage getStage() {
		return mStage;
	}



	private static final String TAG = SDCardUtil.class.getSimpleName();


	private static final String TAG_SMIL = "smil";
	private static final String TAG_PAR = "par";
	private static final String TAG_SEQ = "seq";
	private static final String TAG_AUDIO = "audio";
	private static final String TAG_IMG = "img";
	private static final String TAG_TEXT = "text";

	private static final String TAG_PARAMETER = "param";


	private CharArrayWriter mContents = new CharArrayWriter();
	private Stack<Object> mStack=new Stack<Object>();
	private Stage mStage;
	private boolean mCollectContent=false;

}
